package com.aaa.gs.filter;

import com.aaa.common.util.Result;
import com.aaa.common.util.ResultStatus;
import com.aaa.gs.service.RemoteAuthService;
import com.alibaba.fastjson.JSON;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;
import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.Map;

/**
 * @ fileName:SingleLoginFilter
 * @ description:
 * @ author:诸葛龙辰
 * @ createTime:2023/6/17 9:33
 * @ version:1.0.0
 */
@Component
public class SingleLoginFilter implements GlobalFilter, Ordered {

    //获取配置值，并注入到whiteList属性
    @Value("${white-list}")
    private String whiteList;

    //定义常量，不能更改，要求前端必须在头或者请求参数中含有名称为token的参数
    private  final  String   REQUEST_TOKEN="token";

    @Resource
    private RemoteAuthService remoteAuthService;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //获取request和response
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        //url: http://localhost:16450/user/checkToken?token=admin-eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJhZG1pbiIsInVzZXJOYW1lIjoiYWRtaW4iLCJ1c2VySWQiOiIxIiwiaWF0IjoxNjg2OTY1NDM0fQ.jcOBxJU7b-6Yy6Hb8HXa_1TfS8K9flRRKgL2O-gG4Eg
        //uri: /user/checkToken
        //使用request对象获取请求uri
        String uri = request.getURI().getPath();
        System.out.println("请求的uri:"+uri);
        //"user/login,/user/checkToken,/member/login,/member/checkToken,/order/queryById".contains("/user/checkToken")
        //1,判断白名单中是否含有请求的地址  含有，直接放行
        if(whiteList.contains(uri)){
            return chain.filter(exchange);
        }
        //定义token
        String  token = null;
        //2,获取请求中携带的token 如果获取不到，说明没有带   如果获取到，再判断是否正确
            //2.1 获取携带的token   先从请求header获取
        List<String> tokenList = request.getHeaders().get(REQUEST_TOKEN);
            //  判断tokenList是否为null
        if(!CollectionUtils.isEmpty(tokenList)){
            //获取token
            token = tokenList.get(0);
        }
           //2.2 再次判断token是否为null，如果依然为null说明header没有携带   再从参数中获取
        if(token==null){
              //获取所有参数及值
              MultiValueMap<String, String> queryParamsMap = request.getQueryParams();
              //判断是否为null，循环遍历
              if(queryParamsMap!=null&&queryParamsMap.size()>0){
                  ///order/queryById?id=1&aa=11&bb=22&cc=33&token=xxx.xxx.xx
                  //queryParamsMap.put("id",1);queryParamsMap.put("bb",22);queryParamsMap.put("cc",33);....
                  for (Map.Entry<String, List<String>> stringListEntry : queryParamsMap.entrySet()) {
                      //key 第1次 id   第2次 aa   第3次 bb  第4次 token ......
                      String key = stringListEntry.getKey();
                      if(REQUEST_TOKEN.equals(key)) {
                          //value 第1次 [1]  第2次 [11]  第3次 [22]   第4次 [xxx.xxx.xx]  ....
                          List<String> valueList = stringListEntry.getValue();
                          token=valueList.get(0);
                          //找到就跳出循环，后面不用管
                          break;
                      }
                  }
              }
          }

        // 请求有问题，阻止请求继续
        //token依然为null说明没有携带  没有携带提示错误，如果携带，判断token是否正确（如果不正确提示错误，如果正确放行）
        if(token==null||!remoteAuthService.checkToken(token)){
            //定义返回map对象
            Result result =new Result(ResultStatus.NO_AUTH_ERROR.getReturnCode(),
                    ResultStatus.NO_AUTH_ERROR.getReturnMsg(),"你没有登录！");
            byte[] bytesMap = null;
            try {
                //把map转换为字节数组
                bytesMap = JSON.toJSONString(result).getBytes("GBK");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            //spring 提供数据缓冲类  使用response.bufferFactory()中提供的wrap方法，把字节数组转换为DataBuffer
            DataBuffer dataBuffer = response.bufferFactory().wrap(bytesMap);
            //writeWith 向响应对象中写入影响数据  需要的是Publisher接口的实现类   Mono就是该接口的实现类
            return response.writeWith(Mono.just(dataBuffer));
        }
        //让程序继续运行
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        //在非法IP之后  ，在非法字符之前
        return 7;
    }
}
